home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / net_src.arc / smtpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-08  |  17.6 KB  |  799 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <time.h>
  6. #ifdef __TURBOC__
  7. #include <fcntl.h>
  8. #endif
  9. #ifdef UNIX
  10. #include <sys/types.h>
  11. #endif
  12. #include <ctype.h>
  13. #include "global.h"
  14. #include "mbuf.h"
  15. #include "netuser.h"
  16. #include "timer.h"
  17. #include "tcp.h"
  18. #include "smtp.h"
  19.  
  20. char *getname();
  21. void mail_delete();
  22. static int rqueuejob();
  23. int queuejob();
  24. int validate_address();
  25. long get_msgid();
  26. struct list *addlist();
  27. struct list * expandalias();
  28.  
  29. /* Command table */
  30. static char *commands[] = {
  31.     "helo",
  32. #define    HELO_CMD    0
  33.     "noop",
  34. #define    NOOP_CMD    1
  35.     "mail from:",
  36. #define    MAIL_CMD    2
  37.     "quit",
  38. #define    QUIT_CMD    3
  39.     "rcpt to:",
  40. #define    RCPT_CMD    4
  41.     "help",
  42. #define    HELP_CMD    5
  43.     "data",
  44. #define    DATA_CMD    6
  45.     "rset",
  46. #define    RSET_CMD    7
  47.     NULLCHAR
  48. };
  49.  
  50. /* Reply messages */
  51. static char help[] = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  52. static char banner[] = "220 %s SMTP ready\r\n";
  53. static char closing[] = "221 Closing\r\n";
  54. static char ok[] = "250 Ok\r\n";
  55. static char reset[] = "250 Reset state\r\n";
  56. static char sent[] = "250 Sent\r\n";
  57. static char ourname[] = "250 %s, Share and Enjoy!\r\n";
  58. static char enter[] = "354 Enter mail, end with .\r\n";
  59. static char ioerr[] = "452 Temp file write error\r\n";
  60. static char mboxerr[] = "452 Mailbox write error\r\n";
  61. static char badcmd[] = "500 Command unrecognized\r\n";
  62. static char syntax[] = "501 Syntax error\r\n";
  63. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  64. static char unknown[] = "550 <%s> address unknown\r\n";
  65.  
  66. static struct tcb *smtp_tcb;
  67. /* Start up SMTP receiver service */
  68. smtp1(argc,argv)
  69. int argc;
  70. char *argv[];
  71. {
  72.     struct socket lsocket;
  73.     void r_mail(),s_mail();
  74.  
  75.     lsocket.address = ip_addr;
  76.     if(argc < 2)
  77.         lsocket.port = SMTP_PORT;
  78.     else
  79.         lsocket.port = atoi(argv[1]);
  80.  
  81.     smtp_tcb = open_tcp(&lsocket,NULLSOCK,
  82.         TCP_SERVER,0,r_mail,NULLVFP,s_mail,0,(char *)NULL);
  83. }
  84.  
  85. /* Shutdown SMTP service (existing connections are allowed to finish) */
  86. smtp0()
  87. {
  88.     if(smtp_tcb != NULLTCB)
  89.         close_tcp(smtp_tcb);
  90. }
  91.  
  92. /* SMTP connection state change upcall handler */
  93. static void
  94. s_mail(tcb,old,new)
  95. struct tcb *tcb;
  96. char old,new;
  97. {
  98.     struct mail *mp,*mail_create();
  99.  
  100.     switch(new){
  101. #ifdef    QUICKSTART
  102.     case SYN_RECEIVED:
  103. #else
  104.     case ESTABLISHED:
  105. #endif
  106.         if((mp = mail_create(tcb)) == NULLMAIL){
  107.             close_tcp(tcb);
  108.             break;
  109.         }
  110.         (void) tprintf(mp->tcb,banner,hostname);
  111.         log(tcb,"open SMTP");
  112.         break;        
  113.     case CLOSE_WAIT:
  114.         close_tcp(tcb);
  115.         break;
  116.     case CLOSED:
  117.         log(tcb,"close SMTP");
  118.         mp = (struct mail *)tcb->user;
  119.         mail_delete(mp);                
  120.         del_tcp(tcb);
  121.         /* Check if server is being shut down */
  122.         if(tcb == smtp_tcb)
  123.             smtp_tcb = NULLTCB;
  124.         break;
  125.     }
  126. }
  127.  
  128. /* SMTP receiver upcall handler */
  129. static void
  130. r_mail(tcb,cnt)
  131. struct tcb *tcb;
  132. int16 cnt;
  133. {
  134.     register struct mail *mp;
  135.     char c;
  136.     struct mbuf *bp;
  137.     char *inet_ntoa();
  138.     void docommand(),doline();
  139.  
  140.     if((mp = (struct mail *)tcb->user) == NULLMAIL){
  141.         /* Unknown session */
  142.         close_tcp(tcb);
  143.         return;
  144.     }
  145.     recv_tcp(tcb,&bp,cnt);
  146.     /* Assemble an input line in the session buffer.
  147.      * Return if incomplete
  148.      */
  149.     while(pullup(&bp,&c,1) == 1){
  150.         switch(c){
  151.         case '\r':    /* Strip cr's */
  152. #ifdef MSDOS
  153.         case '\032':    /* Strip ctrl/Z's */
  154. #endif
  155.             continue;
  156.         case '\n':    /* Complete line; process it */
  157.             mp->buf[mp->cnt] = '\0';
  158.             doline(mp);
  159.             break;
  160.         default:    /* Assemble line */
  161.             if(mp->cnt != LINELEN-1)
  162.                 mp->buf[mp->cnt++] = c;
  163.             break;
  164.         }
  165.     }
  166. }
  167. /* Process a line read on an SMTP connection (any state) */
  168. static void
  169. doline(mp)
  170. register struct mail *mp;
  171. {
  172.     void docommand(),deliver();
  173.  
  174.     switch(mp->state){
  175.     case COMMAND_STATE:
  176.         docommand(mp);
  177.         break;
  178.     case DATA_STATE:
  179.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  180.         if(mp->buf[0] == '.' && mp->buf[1] == '\0'){
  181.             mp->state = COMMAND_STATE;
  182.         /* Also sends appropriate response */
  183.             deliver(mp);
  184.             fclose(mp->data);
  185.             mp->data = NULLFILE;
  186.             del_list(mp->to);
  187.             mp->to = NULLLIST;
  188.             break;
  189.         }
  190.         /* for UNIX mail compatiblity */
  191.         if (strncmp(mp->buf,"From ",5) == 0)
  192.             (void) putc('>',mp->data);
  193.         /* Append to data file */
  194.         if(fprintf(mp->data,"%s\n",mp->buf) < 0){
  195.             mp->state = COMMAND_STATE;
  196.             (void) tprintf(mp->tcb,ioerr);
  197.         }
  198.         break;
  199.     }
  200.     mp->cnt = 0;
  201. }
  202. /* Create control block, initialize */
  203. static struct mail *
  204. mail_create(tcb)
  205. register struct tcb *tcb;
  206. {
  207.     register struct mail *mp;
  208.  
  209.     if((mp = (struct mail *)calloc(1,sizeof (struct mail))) == NULLMAIL)
  210.         return NULLMAIL;
  211.     mp->tcb = tcb;        /* Downward pointer */
  212.     tcb->user = (char *)mp;    /* Upward pointer */
  213.     return mp;
  214. }
  215.  
  216. /* Free resources, delete control block */
  217. static void
  218. mail_delete(mp)
  219. register struct mail *mp;
  220. {
  221.  
  222.     if (mp == NULLMAIL)
  223.         return;
  224.     if(mp->system != NULLCHAR)
  225.         free(mp->system);
  226.     if(mp->from != NULLCHAR)
  227.         free(mp->from);
  228.     if(mp->data != NULLFILE)
  229.         fclose(mp->data);
  230.     del_list(mp->to);
  231.     free((char *)mp);
  232. }
  233.  
  234. /* Parse and execute mail commands */
  235. static void
  236. docommand(mp)
  237. register struct mail *mp;
  238. {
  239.     register char **cmdp,*arg,*cp,*cmd;
  240.     struct list *ap;
  241.     FILE *tmpfile();
  242.     long t;
  243.     char address_type;
  244.  
  245.     cmd = mp->buf;
  246.     if(mp->cnt < 4){
  247.         /* Can't be a legal SMTP command */
  248.         (void) tprintf(mp->tcb,badcmd);
  249.         return;
  250.     }    
  251.     cmd = mp->buf;
  252.  
  253.     /* Translate entire buffer to lower case */
  254.     for(cp = cmd;*cp != '\0';cp++)
  255.         *cp = tolower(*cp);
  256.  
  257.     /* Find command in table; if not present, return syntax error */
  258.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  259.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  260.             break;
  261.     if(*cmdp == NULLCHAR){
  262.         (void) tprintf(mp->tcb,badcmd);
  263.         return;
  264.     }
  265.     arg = &cmd[strlen(*cmdp)];
  266.     /* Skip spaces after command */
  267.     while(*arg == ' ')
  268.         arg++;
  269.     /* Execute specific command */
  270.     switch(cmdp-commands){
  271.     case HELO_CMD:
  272.         if(mp->system != NULLCHAR)
  273.             free(mp->system);
  274.         if((mp->system = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  275.             /* If the system is out of memory, just close */
  276.             close_tcp(mp->tcb);
  277.             break;            
  278.         } else {
  279.             strcpy(mp->system,arg);
  280.             (void) tprintf(mp->tcb,ourname,hostname);
  281.         }
  282.         break;
  283.     case NOOP_CMD:
  284.         (void) tprintf(mp->tcb,ok);
  285.         break;
  286.     case MAIL_CMD:
  287.         if(mp->from != NULLCHAR)
  288.             free(mp->from);
  289.         if((mp->from = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  290.             /* If the system is out of memory, just close */
  291.             close_tcp(mp->tcb);
  292.             break;            
  293.         } else {
  294.             if((cp = getname(arg)) == NULLCHAR){
  295.                 (void) tprintf(mp->tcb,syntax);
  296.                 break;
  297.             }
  298.             strcpy(mp->from,cp);
  299.             (void) tprintf(mp->tcb,ok);
  300.         }
  301.         break;
  302.     case QUIT_CMD:
  303.         (void) tprintf(mp->tcb,closing);
  304.         close_tcp(mp->tcb);
  305.         break;
  306.     case RCPT_CMD:    /* Specify recipient */
  307.         if((cp = getname(arg)) == NULLCHAR){
  308.             (void) tprintf(mp->tcb,syntax);
  309.             break;
  310.         }
  311.  
  312.         /* check if address is ok */
  313.         if ((address_type = validate_address(cp)) == BADADDR) {
  314.             (void) tprintf(mp->tcb,unknown,cp);
  315.             break;
  316.         }
  317.         /* if a local address check for an alias */
  318.         if (address_type == LOCAL)
  319.             expandalias(&mp->to, cp);
  320.         else
  321.             /* a remote address is added to the list */
  322.             addlist(&mp->to, cp, address_type);
  323.  
  324.         (void) tprintf(mp->tcb,ok);
  325.         break;
  326.     case HELP_CMD:
  327.         (void) tprintf(mp->tcb,help);
  328.         break;
  329.     case DATA_CMD:
  330.         if(mp->to == NULLLIST){
  331.             (void) tprintf(mp->tcb,needrcpt);
  332.             break;
  333.         }
  334.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  335.         if((mp->data = tmpfile()) == NULLFILE){
  336.             (void) tprintf(mp->tcb,ioerr);
  337.             break;
  338.         }
  339.         /* Add timestamp; ptime adds newline */
  340.         time(&t);
  341.         fprintf(mp->data,"Received: ");
  342.         if(mp->system != NULLCHAR)
  343.             fprintf(mp->data,"from %s ",mp->system);
  344.         fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  345.                 hostname, get_msgid(), ptime(&t));
  346.         if(ferror(mp->data)){
  347.             (void) tprintf(mp->tcb,ioerr);
  348.         } else {
  349.             mp->state = DATA_STATE;
  350.             (void) tprintf(mp->tcb,enter);
  351.         }
  352.         break;
  353.     case RSET_CMD:
  354.         del_list(mp->to);
  355.         mp->to = NULLLIST;
  356.         mp->state = COMMAND_STATE;
  357.         (void) tprintf(mp->tcb,reset);
  358.         break;
  359.     }
  360. }
  361. /* Given a string of the form <user@host>, extract the part inside the
  362.  * brackets and return a pointer to it.
  363.  */
  364. static
  365. char *
  366. getname(cp)
  367. register char *cp;
  368. {
  369.     register char *cp1;
  370.  
  371.     if((cp = index(cp,'<')) == NULLCHAR)
  372.         return NULLCHAR;
  373.     cp++;    /* cp -> first char of name */
  374.     if((cp1 = index(cp,'>')) == NULLCHAR)
  375.         return NULLCHAR;
  376.     *cp1 = '\0';
  377.     return cp;
  378. }
  379.  
  380. /* Deliver mail to the appropriate mail boxes and delete temp file */
  381. static
  382. void
  383. deliver(mp)
  384. register struct mail *mp;
  385. {
  386.     int ret;
  387.  
  388.     /* send to the rqueue */
  389.     if ((smtpmode & QUEUE) != 0) {
  390.         ret = router_queue(mp->tcb,mp->data,mp->from,mp->to);
  391.         if (ret != 0)
  392.             (void) tprintf(mp->tcb,ioerr);
  393.     } else {
  394.         ret = mailit(mp->tcb,mp->data,mp->from,mp->to);
  395.         if (ret != 0)
  396.             (void) tprintf(mp->tcb,mboxerr);
  397.     }
  398.     if (ret == 0)
  399.         (void) tprintf(mp->tcb,sent);
  400.         
  401. }
  402.  
  403. /* used to save local mail or reroute remote mail */
  404. mailit(tcb,data,from,to)
  405. struct tcb *tcb;
  406. FILE *data;
  407. char *from;
  408. struct list *to;
  409. {
  410.     register struct list *ap;
  411.     register FILE *fp;
  412.     int c;
  413.     char    mailbox[50];
  414.     char    *cp;
  415.     char    *desthost;
  416.     int    fail = 0;
  417.     time_t    t;
  418.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  419.  
  420.         fseek(data,0L,0);    /* rewind */
  421.  
  422.         /* non local mail queue it */
  423.         if (ap->type == DOMAIN) {
  424.             if ((desthost = index(ap->val,'@')) != NULLCHAR);
  425.                 desthost++;
  426.             fail = queuejob(tcb,data,desthost,ap->val,from);
  427.         } else {
  428.             /* strip off host name */
  429.             if ((cp = index(ap->val,'@')) != NULLCHAR)
  430.                 *cp = '\0';
  431.  
  432.             /* truncate long user names */
  433.             if (strlen(ap->val) > MBOXLEN)
  434.                 ap->val[MBOXLEN] = '\0';
  435.  
  436.             /* if mail file is busy save it in our smtp queue
  437.              * and let the smtp daemon try later.
  438.              */
  439.             if (mlock(mailspool,ap->val))
  440.                 fail = queuejob(tcb,data,hostname,ap->val,from);
  441.             else {
  442.                 sprintf(mailbox,"%s/%s.txt",mailspool,ap->val);
  443.                 if((fp = fopen(mailbox,"a+")) != NULLFILE) {
  444.                     time(&t);
  445.                     fprintf(fp,
  446.                     "From %s %s",from,ctime(&t));
  447.                     while((c = getc(data)) != EOF)
  448.                         if(putc(c,fp) == EOF)
  449.                             break;
  450.                     if(ferror(fp))
  451.                         fail = 1;
  452.                     else
  453.                         fprintf(fp,"\n");
  454.                     /* Leave a blank line between msgs */
  455.                     fclose(fp);
  456.                     printf("New mail arrived for %s\n",ap->val);
  457.                     fflush(stdout);
  458.                 } else 
  459.                     fail = 1;
  460.                 (void) rmlock(mailspool,ap->val);
  461.                 if (fail)
  462.                     break;
  463.                 log(tcb,
  464.                 "SMTP recv: To: %s From: %s",ap->val,from);
  465.             }
  466.         }
  467.     }
  468.     return(fail) ;
  469. }
  470.  
  471. /* Return Date/Time in Arpanet format in passed string */
  472. char *
  473. ptime(t)
  474. long *t;
  475. {
  476.     /* Print out the time and date field as
  477.      *        "DAY day MONTH year hh:mm:ss ZONE"
  478.      */
  479.     register struct tm *ltm;
  480.     static char tz[4];
  481.     static char str[40];
  482.     extern char *getenv();
  483.     extern struct tm *localtime();
  484.     char *p;
  485.     static char *days[7] = {
  486.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  487.  
  488.     static char *months[12] = {
  489.         "Jan","Feb","Mar","Apr","May","Jun",
  490.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  491.  
  492.     /* Read the system time */
  493.     ltm = localtime(t);
  494.  
  495.     if (*tz == '\0')
  496.         if (((p = getenv("TZ")) == NULL) &&
  497.              (p = getenv("TIMEZONE")) == NULL)
  498.             strcpy(tz,"GMT");
  499.         else
  500.             strncpy(tz,p,3);
  501.  
  502.     /* rfc 822 format */
  503.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  504.         days[ltm->tm_wday],
  505.         ltm->tm_mday,
  506.         months[ltm->tm_mon],
  507.         ltm->tm_year,
  508.         ltm->tm_hour,
  509.         ltm->tm_min,
  510.         ltm->tm_sec,
  511.         tz);
  512.     return(str);
  513. }
  514.  
  515. long 
  516. get_msgid()
  517. {
  518.     char sfilename[LINELEN];
  519.     char s[20];
  520.     register long sequence = 0;
  521.     FILE *sfile;
  522.     long atol();
  523.  
  524.     sprintf(sfilename,"%s/sequence.seq",mailqdir);
  525.     sfile = fopen(sfilename,"r");
  526.  
  527.     /* if sequence file exists, get the value, otherwise set it */
  528.     if (sfile != NULL) {
  529.         (void) fgets(s,sizeof(s),sfile);
  530.         sequence = atol(s);
  531.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  532.         if (sequence < 0L || sequence > 99999999L )
  533.             sequence = 0;
  534.         fclose(sfile);
  535.     }
  536.  
  537.     /* increment sequence number, and write to sequence file */
  538.     sfile = fopen(sfilename,"w");
  539.     fprintf(sfile,"%ld",++sequence);
  540.     fclose(sfile);
  541.     return sequence;
  542. }
  543.  
  544. #ifdef    MSDOS
  545. /* Illegal characters in a DOS filename */
  546. static char baddoschars[] = "\"[]:|<>+=;,";
  547. #endif
  548.  
  549. /* test if mail address is valid */
  550. int
  551. validate_address(s)
  552. char *s;
  553. {
  554.     FILE *fp;
  555.     char *cp;
  556.     int32 addr;
  557.     char    address_type;
  558.     int32 mailroute();
  559.  
  560.  
  561.  
  562.     /* if address has @ in it the check dest address */
  563.     if ((cp = index(s,'@')) != NULLCHAR) {
  564.         cp++;
  565.         /* 1st check if its our hostname
  566.         * if not then check the hosts file and see
  567.         * if we can resolve ther address to a know site
  568.         * or one of our aliases
  569.         */
  570.         if (strcmp(cp,hostname) != 0) {
  571.             if ((addr = mailroute(cp)) == 0
  572.                 && (smtpmode & QUEUE) == 0)
  573.                 return BADADDR;
  574.             if (addr != ip_addr)
  575.                 return DOMAIN;
  576.         }
  577.         
  578.         /* on a local address remove the host name part */
  579.         *--cp = '\0';
  580.     }
  581.  
  582.     /* if using an external router leave address alone */
  583.     if ((smtpmode & QUEUE) != 0)
  584.         return LOCAL;
  585.  
  586.  
  587.     /* check for the user%host hack */
  588.     if ((cp = index(s,'%')) != NULLCHAR) {
  589.         *cp = '@';
  590.         cp++;
  591.         /* reroute based on host name following the % seperator */
  592.         if (mailroute(cp) == 0)
  593.             return BADADDR;
  594.         else
  595.             return DOMAIN;
  596.     }
  597.     address_type = LOCAL;
  598.  
  599. #ifdef MSDOS    /* dos file name checks */
  600.     /* Check for characters illegal in MS-DOS file names */
  601.     for(cp = baddoschars;*cp != '\0';cp++){
  602.         if(index(s,*cp) != NULLCHAR)
  603.             return BADADDR;    
  604.     }
  605. #endif
  606.     return LOCAL;
  607. }
  608.  
  609. /* place a mail job in the outbound queue */
  610. int
  611. queuejob(tcb,dfile,host,to,from)
  612. struct tcb *tcb;
  613. FILE *dfile;
  614. char *host,*to,*from;
  615. {
  616.     FILE *fp;
  617.     char tmpstring[50];
  618.     char prefix[9];
  619.     register int c;
  620.  
  621.     sprintf(prefix,"%ld",get_msgid());
  622.     log(tcb,"SMTP queue job %s To: %s From: %s",prefix,to,from);
  623.     mlock(mailqdir,prefix);
  624.     sprintf(tmpstring,"%s/%s.txt",mailqdir,prefix);
  625.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  626.         (void) rmlock(mailqdir,prefix);
  627.         return 1;
  628.     }
  629.     while((c = getc(dfile)) != EOF)
  630.         if(putc(c,fp) == EOF)
  631.             break;
  632.     if(ferror(fp)){
  633.         fclose(fp);
  634.         (void) rmlock(mailqdir,prefix);
  635.         return 1;
  636.     }
  637.     fclose(fp);
  638.     sprintf(tmpstring,"%s/%s.wrk",mailqdir,prefix);
  639.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  640.         (void) rmlock(mailqdir,prefix);
  641.         return 1;
  642.     }
  643.     fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  644.     fclose(fp);
  645.     (void) rmlock(mailqdir,prefix);
  646.     return 0;
  647. }
  648.  
  649. /* Deliver mail to the appropriate mail boxes */
  650. int
  651. router_queue(tcb,data,from,to)
  652. struct tcb *tcb;
  653. FILE *data;
  654. char *from;
  655. struct list *to;
  656. {
  657.     int c;
  658.     register struct list *ap;
  659.     FILE *fp;
  660.     char tmpstring[50];
  661.     char prefix[9];
  662.  
  663.     sprintf(prefix,"%ld",get_msgid());
  664.     mlock(routeqdir,prefix);
  665.     sprintf(tmpstring,"%s/%s.txt",routeqdir,prefix);
  666.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  667.         (void) rmlock(routeqdir,prefix);
  668.         return 1;
  669.     }
  670.     fseek(data,0L,0);    /* rewind */
  671.     while((c = getc(data)) != EOF)
  672.         if(putc(c,fp) == EOF)
  673.             break;
  674.     if(ferror(fp)){
  675.         fclose(fp);
  676.         (void) rmlock(routeqdir,prefix);
  677.         return 1;
  678.     }
  679.     fclose(fp);
  680.     sprintf(tmpstring,"%s/%s.wrk",routeqdir,prefix);
  681.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  682.         (void) rmlock(routeqdir,prefix);
  683.         return 1;
  684.     }
  685.     fprintf(fp,"From: %s\n",from);
  686.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  687.         fprintf(fp,"To: %s\n",ap->val);
  688.     }
  689.     fclose(fp);
  690.     (void) rmlock(routeqdir,prefix);
  691.     log(tcb,"SMTP rqueue job %s From: %s",prefix,from);
  692.     return 0;
  693. }
  694.  
  695. /* add an element to the front of the list pointed to by head 
  696. ** return NULLLIST if out of memory.
  697. */
  698. struct list *
  699. addlist(head,val,type)
  700. struct list **head;
  701. char *val;
  702. int type;
  703. {
  704.     register struct list *tp;
  705.  
  706.     tp = (struct list *)calloc(1,sizeof(struct list));
  707.     if (tp == NULLLIST)
  708.         return NULLLIST;
  709.  
  710.     tp->next = NULLLIST;
  711.  
  712.     /* allocate storage for the char string */
  713.     if ((tp->val = malloc((unsigned)strlen(val)+1)) == NULLCHAR) {
  714.         (void) free((char *)tp);
  715.         return NULLLIST;
  716.     }
  717.     strcpy(tp->val,val);
  718.     tp->type = type;
  719.  
  720.     /* add entry to front of existing list */
  721.     if (*head == NULLLIST)
  722.         *head = tp;
  723.     else {
  724.         tp->next = *head;
  725.         *head = tp;
  726.     }
  727.     return tp;
  728.  
  729. }
  730.  
  731. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  732. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  733.  
  734. /* check for and alias and expand alias into a address list */
  735. struct list *
  736. expandalias(head, user)
  737. struct list **head;
  738. char *user;
  739. {
  740.     FILE *fp;
  741.     register char *s,*p,*h;
  742.     int inalias;
  743.     struct list *tp;
  744.     char buf[LINELEN];
  745.     
  746.     
  747.         /* no alias file found */
  748.     if ((fp = fopen(alias, "r")) == NULLFILE)
  749.         return addlist(head, user, LOCAL);
  750.  
  751.     inalias = 0;
  752.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  753.         p = buf;
  754.         if ( *p == '#' || *p == '\0')
  755.             continue;
  756.         rip(p);
  757.  
  758.         /* if not in an matching entry skip continuation lines */
  759.         if (!inalias && isspace(*p))
  760.             continue;
  761.  
  762.         /* when processing an active alias check for a continuation */
  763.         if (inalias) {
  764.             if (!isspace(*p)) 
  765.                 break;    /* done */
  766.         } else {
  767.             s = p;
  768.             SKIPWORD(p);
  769.             *p++ = '\0';    /* end the alias name */
  770.             if (strcmp(s,user) != 0)
  771.                 continue;    /* no match go on */
  772.             inalias = 1;
  773.         }
  774.  
  775.         /* process the recipients on the alias line */
  776.         SKIPSPACE(p);
  777.         while(*p != '\0' && *p != '#') {
  778.             s = p;
  779.             SKIPWORD(p);
  780.             if (*p != '\0')
  781.                 *p++ = '\0';
  782.  
  783.             /* find hostname */
  784.             if ((h = index(s,'@')) != NULLCHAR)
  785.                 tp = addlist(head,s,DOMAIN);
  786.             else
  787.                 tp = addlist(head,s,LOCAL);
  788.             SKIPSPACE(p);
  789.         }
  790.     }
  791.     (void) fclose(fp);
  792.  
  793.     if (inalias)    /* found and processed and alias. */
  794.         return tp;
  795.  
  796.     /* no alias found treat as a local address */
  797.     return addlist(head, user, LOCAL);
  798. }
  799.